import data from "../../../../core/cache_data";
import { MouseInfo, TouchHandle } from "../../../../core/data_ext";
import { ReplacePageAni } from "../../../../core/game";
import { Library } from "../../../../core/library";
import SerializeAble from "../../../../core/serialize";
import Utils, { Sync } from "../../../../core/utils";
import CheckBox from "../../../../prefabs/check_box";
import RadioGroup2 from "../../../../prefabs/radio_group2";
import MutiTouch from "../../../some_good_prefab/assets/muti_touch";
import Bullet from "../../bullet";
import { GetEditorAttrListByTarget } from "../../bullet_editor_attribute";
import World from "../../world";
import { WorldData, WorldDataReadWrite } from "../../world_data";
import BoxLoadWorld from "../box_load_world/box_load_world";
import BulletAttrItem from "../editor/bullet_attr_item";
import BulletInfo from "../editor/bullet_info";
import { BulletGameUtils } from "../game/bullet_game_utils";
import { GameData } from "../game/game_data";
import Interface from "../game/interface";
import BulletList from "./bullet_list";
import EditorToolItem, { EditorToolInfo, EditorToolItemFunc } from "./editor_tool_item";
import WorldConfigPanel from "./world_config_panel";

const { executeInEditMode, ccclass, property } = cc._decorator;

export const MapEditorTiles = [
    "brick",
    "light_bulb",
    "rope"
];
@ccclass
// @executeInEditMode
export default class PageMapEditor extends cc.Component {
    world: World = null;
    @property(cc.Label)
    lbCoord: cc.Label = null;
    @property(cc.Label)
    lbCoordWorld: cc.Label = null;
    @property(cc.Node)
    coordCursor: cc.Node = null;

    @property(cc.Label)
    lbZoom: cc.Label = null;
    @property(cc.Label)
    lbPos: cc.Label = null;
    @property(Interface)
    interface: Interface = null;
    @property(cc.Prefab)
    toolItemPrefab: cc.Prefab = null;
    @property(cc.Graphics)
    drawer: cc.Graphics = null;

    @property(cc.EditBox)
    ebOffsetX: cc.EditBox = null;
    @property(cc.EditBox)
    ebOffsetY: cc.EditBox = null;

    @property(CheckBox)
    cbGrid: CheckBox = null;

    gridOffset = cc.v2(50, 50);
    onEditOffset() {
        this.gridOffset.x = Number(this.ebOffsetX.string) || 0;
        this.gridOffset.y = Number(this.ebOffsetY.string) || 0;
    }

    @property(cc.EditBox)
    ebWorldWidth: cc.EditBox = null;
    @property(cc.EditBox)
    ebWorldHeight: cc.EditBox = null;
    @property(cc.EditBox)
    ebWorldGravityX: cc.EditBox = null;
    @property(cc.EditBox)
    ebWorldGravityY: cc.EditBox = null;

    @property(BulletList)
    bulletList: BulletList = null;

    @property(cc.Node)
    attrContain: cc.Node = null;
    @property(cc.Prefab)
    attrItemPrefab: cc.Prefab = null;
    @property(cc.Prefab)
    attrItemVec2Prefab: cc.Prefab = null;
    @property(cc.Prefab)
    attrItemBooleanPrefab: cc.Prefab = null;

    @property(RadioGroup2)
    rdTool: RadioGroup2 = null;
    @property(RadioGroup2)
    rdTool2: RadioGroup2 = null;

    // @property(cc.Node)
    // copyShadow: cc.Node = null;

    @property(BulletInfo)
    bulletInfo: BulletInfo = null;

    @property(WorldConfigPanel)
    worldConfigPanel: WorldConfigPanel = null;
    @property(WorldConfigPanel)
    newWorldConfigPanel: WorldConfigPanel = null;


    mouseInfo: MouseInfo = new MouseInfo();
    mutiTouch: MutiTouch = null;

    // curToolItem: EditorToolItem = null;
    get curToolInfo() {
        return this._toolInfoStack[0];
    }
    set curToolInfo(val) {
        this._toolInfoStack[0] = val;
    }
    unshiftToolInfo(val) {
        this._toolInfoStack.unshift(val);
    }
    shiftToolInfo() {
        return this._toolInfoStack.shift();
    }
    _toolInfoStack: EditorToolInfo[] = [];

    worldCoord: cc.Vec2 = null;

    dragPos = cc.v2();
    bullets: Bullet[] = [];
    protected _selectBullets: Bullet[] = [];

    private __normalStrokeColor: cc.Color = null;
    private __normalFillColor: cc.Color = null;

    isLogin = false;
    moveDelta = 100;
    @property(cc.Node)
    shiftNode: cc.Node = null;
    @property(cc.Node)
    ctrlNode: cc.Node = null;
    @property(cc.Node)
    altNode: cc.Node = null;

    mapEditorDataStack: WorldData[] = [];
    pushHistroy(data: WorldData) {
        this.mapEditorDataStack.push(data);
        if (this.mapEditorDataStack.length > 20) {
            this.mapEditorDataStack.shift();
        }
    }
    popHistroy() {
        if (this.mapEditorDataStack.length > 0) {
            return this.mapEditorDataStack.pop();
        }
        else {
            return null;
        }
    }

    @property(CheckBox)
    cbNew: CheckBox = null;

    onClickCbNew() {
        if (this.cbNew.checked) {
            let config = new WorldData;
            this.newWorldConfigPanel.setData(config);
        }
    }

    protected onDisable(): void {
        cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
        cc.systemEvent.off(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
    }
    protected onEnable(): void {
        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
    }

    //从bulletList中的消息
    onSelectBullet(bullet: Bullet) {
        this.selectBullet(bullet);
    }
    //从bulletList中的消息
    onDeleteBullet(bullet: Bullet) {
        this.delBullet(bullet);
    }
    async onLoad() {
        this.cbGrid.checked = data.storage.get("editor-grid", true);
        this.cbGrid.on("clicked", () => {
            data.storage.set("editor-grid", this.cbGrid.checked);
        }, this);
        this.__normalStrokeColor = this.drawer.strokeColor.clone();
        this.__normalFillColor = this.drawer.fillColor.clone();

        this.bulletList.on("select-bullet", this.onSelectBullet, this);
        this.bulletList.on("delete-bullet", this.onDeleteBullet, this);
        this.cbNew.on("clicked", this.onClickCbNew, this);
        this.interface.minZoom = 0.1;
        this.interface.maxZoom = 10;

        if (!CC_EDITOR) {
            this.mutiTouch = this.addComponent(MutiTouch);
        }

        this.mutiTouch.on("start", this.onTouchStart, this);
        this.mutiTouch.on("single-move", this.onTouchSingleMove, this);
        this.mutiTouch.on("muti-move", this.onTouchMutiMove, this);
        this.mutiTouch.on("end", this.onTouchEnd, this);
        this.node.on(cc.Node.EventType.MOUSE_MOVE, this.onMouseMove, this);
        this.node.on(cc.Node.EventType.MOUSE_DOWN, this.onMouseDown, this);
        this.node.on(cc.Node.EventType.MOUSE_UP, this.onMouseUp, this);
        this.node.on(cc.Node.EventType.MOUSE_WHEEL, this.onMouseWheel, this);

        for (let i = 0; i < MapEditorTiles.length; i++) {
            let key = MapEditorTiles[i];

            let item = cc.instantiate(this.toolItemPrefab).getComponent(EditorToolItem);
            item.info = new EditorToolInfo();
            item.info.func = EditorToolItemFunc.Tile;
            item.info.ext = key;
            item.lb.string = key;

            let node = BulletGameUtils.InstantiateBullet(key, Bullet).node;
            Utils.ChangeGroupRec(item.node.group, item.node.groupIndex, node);
            node.getComponents(cc.Component).concat(node.getComponentsInChildren(cc.Component)).forEach(com => {
                if (com instanceof cc.RenderComponent) {
                }
                else {
                    com.destroy();
                }
            });
            let box = node.getBoundingBox();
            node.scale = Math.min(item.node.height / box.height, item.node.width / box.width);

            item.node.addChild(node);
            this.rdTool.root.addChild(item.node);
        }
        this.rdTool.on("select", this.onSelectTool, this);
        this.rdTool2.on("select", this.onSelectTool, this);
        this.onSelectTool(0);

        let ind = data.storage.get("editor-world-ind", -1);
        if (ind !== -1) {
            this.loadConfigByInd(ind);
        }
        else {
            let wd = new WorldData();
            wd.key = "unname-map";
            wd.name = "unname";
            wd.desc = "undesc";
            wd.data = "";
            this.newConfig(wd);
        }
    }

    async deleteWorld() {
        this.bulletList.setData(null);
        if (this.world) {
            this.world.node.destroy();
            this.world = null;
            this._selectBullets = [];
        }
    }
    refresh() {
        this.worldConfigPanel.setData(this.world.data);
        this.ebWorldWidth.string = `${Math.floor(this.world.node.width / 100)}`;
        this.ebWorldHeight.string = `${Math.floor(this.world.node.height / 100)}`;
        this.ebWorldGravityX.string = `${Math.floor(this.world.gravity.x / 100)}`;
        this.ebWorldGravityY.string = `${Math.floor(this.world.gravity.y / 100)}`;

        this.bulletList.setData(this.world);
    }
    onEditWorldGravity() {
        let x = Number(this.ebWorldGravityX.string);
        let y = Number(this.ebWorldGravityY.string);

        if (!isNaN(x) && !isNaN(y)) {
            this.world.gravity.x = x * 100;
            this.world.gravity.y = y * 100;
        }
    }
    onEditWorldSize() {
        let w = Number(this.ebWorldWidth.string);
        let h = Number(this.ebWorldHeight.string);

        if (!isNaN(w) && !isNaN(h)) {
            this.world.node.width = w * 100;
            this.world.node.height = h * 100;
        }
    }

    onSelectTool(toolInd: number) {
        let item = this.rdTool.root.children[toolInd].getComponent(EditorToolItem);
        if (!item) {
            return;
        }
        this.curToolInfo = item.info;
    }
    _copyingBullets: Bullet[] = [];
    _copyingPosOffset: cc.Vec2[] = [];
    onKeyDown(evt: cc.Event.EventKeyboard) {
        switch (evt.keyCode) {
            case cc.macro.KEY.a:
                if (this._selectBullets.length > 0) {
                    this._selectBullets = [];
                }
                else {
                    this._selectBullets = this.bullets;
                }
                console.log(`已选择${this._selectBullets.length}个对象`);
                break;
            case cc.macro.KEY.q:
                this.rdTool.select(0);
                break;
            case cc.macro.KEY.s:
                this.rdTool.select(1);
                break;
            case cc.macro.KEY.g:
                this.rdTool.select(2);
                break;
            case cc.macro.KEY.r:
                this.rdTool.select(3);
                break;
            case cc.macro.KEY.c:
                if (this.curToolInfo.func === EditorToolItemFunc.CopyPaste) {
                    this.shiftToolInfo();
                    this._copyingPosOffset = [];
                    this._copyingBullets = [];
                }
                else {
                    if (this._selectBullets.length > 0) {
                        let tp = this.worldCoord.mul(100);
                        this._copyingPosOffset = [];
                        this._copyingBullets = [];
                        this._selectBullets.forEach((bullet, ind) => {
                            this._copyingPosOffset[ind] = tp.sub(bullet.curPos);
                            let copyBullet = cc.instantiate(bullet.node).getComponent(Bullet);
                            this.copyAttr(bullet, copyBullet);
                            this._copyingBullets.push(copyBullet);
                            console.log("复制BULLET:", `${this._copyingPosOffset[ind]}`);
                        });
                        let info = new EditorToolInfo();
                        info.func = EditorToolItemFunc.CopyPaste;
                        info.ext = "";
                        this.unshiftToolInfo(info);
                    }
                }
                break;
            case cc.macro.KEY.Delete:
                this._selectBullets.forEach((bullet, ind) => {
                    this.delBullet(bullet);
                });

                break;
            case cc.macro.KEY.shift:
                this.shiftNode.active = true;
                break;
            case cc.macro.KEY.ctrl:
                this.ctrlNode.active = true;
                break;
            case cc.macro.KEY.alt:
                this.altNode.active = true;
                break;
            case cc.macro.KEY.z:
                this.revocation();
                break;
        }
    }
    onKeyUp(evt: cc.Event.EventKeyboard) {
        switch (evt.keyCode) {
            case cc.macro.KEY.shift:
                this.shiftNode.active = false;
                break;
            case cc.macro.KEY.ctrl:
                this.ctrlNode.active = false;
                break;
            case cc.macro.KEY.alt:
                this.altNode.active = false;
                break;
        }
    }
    //撤销
    revocation() {
        let config = this.popHistroy();
        if (config) {
            this.bullets.forEach(bullet => {
                this.delBullet(bullet);
            });
            this.bullets = [];
            WorldDataReadWrite.ReadDataToWorld(this.world, config.data);
        }
    }
    copyAttr(from: Bullet, to: Bullet) {
        to.tag = from.tag;
        //@ts-ignore
        let eac = GetEditorAttrListByTarget(to);
        if (eac) {
            eac.items.forEach(item => {
                let key = item.property;
                to[key] = from[key];
            })
        }
    }

    onMouseUp(evt: cc.Event.EventMouse) {
        this.mouseInfo.update(evt);
        switch (this.curToolInfo?.func) {
            case EditorToolItemFunc.Cursor:
                if (this.holdingBullets.length > 0) {
                    this.selectBullet(this.holdingBullets[this.holdingInd]);
                    this.holdingBullets = [];
                }
                break;
            case EditorToolItemFunc.Move:
            case EditorToolItemFunc.Size:
                // this.setCurBullet(null);
                // this.dragPos = cc.v2();
                break;
            case EditorToolItemFunc.Delete:
                if (this.holdingBullets.length > 0) {
                    this.selectBullet(this.holdingBullets[this.holdingInd]);
                    this.holdingBullets = [];
                }
                if (this._selectBullets.length > 0) {
                    this._selectBullets.forEach(bullet => {
                        this.delBullet(bullet);
                        this.pushHistroy(this._save());
                    })
                }
        }
    }
    addBullet(bullet: Bullet) {
        bullet.enterWorld(this.world);
        this.bullets.push(bullet);
        bullet.isCreateFromEditor = true;
        this.bulletList.addItem(bullet);
    }
    delBullet(bullet: Bullet) {
        cc.js.array.remove(this.bullets, bullet);
        bullet.node.destroy();
        this.bulletList.delItem(bullet);
        this.unselectBullet(bullet);
    }
    onMouseDown(evt: cc.Event.EventMouse) {
        this.mouseInfo.update(evt);
        switch (this.curToolInfo?.func) {
            case EditorToolItemFunc.BornPoint:
                if (this.mouseInfo.btnLeft) {
                    let wp = this.world.node.convertToWorldSpaceAR(this.worldCoord.mul(100));
                    let np = this.world.node.convertToNodeSpaceAR(wp);
                    this.world.data.bornPointX = Math.floor(np.x / 100);
                    this.world.data.bornPointY = Math.floor(np.y / 100);
                }
                break;

            case EditorToolItemFunc.Cursor:
                if (this.mouseInfo.btnLeft) {
                    this.findBulletByCoord();
                }
                break;
            case EditorToolItemFunc.Tile:
                if (this.mouseInfo.btnLeft) {
                    console.log(`${this.worldCoord}`);
                    let bullet = BulletGameUtils.InstantiateBullet(this.curToolInfo.ext, Bullet);
                    this.addBullet(bullet);

                    bullet.curPos = this.worldCoord.mul(100);
                    this.pushHistroy(this._save());
                    this.selectBullet(bullet);
                }
                break;
            case EditorToolItemFunc.Size:
            case EditorToolItemFunc.Move:
                // if (this.mouseInfo.btnLeft) {
                //     this.findBulletByCoord();
                // }
                break;
            case EditorToolItemFunc.CopyPaste:
                if (this.mouseInfo.btnLeft) {
                    if (this._copyingBullets.length > 0) {
                        this.updateCoord();
                        let tp = this.worldCoord.mul(100);

                        this._copyingBullets.forEach((bullet, ind) => {
                            let offset = this._copyingPosOffset[ind];
                            let pos = tp.add(offset);

                            this.addBullet(bullet);
                            bullet.curPos = pos;
                        });
                        this._copyingBullets = [];
                        this._copyingPosOffset = [];
                    }
                }
                this.shiftToolInfo();

                break;
            case EditorToolItemFunc.Delete:
                if (this.mouseInfo.btnLeft) {
                    this.updateCoord();
                    this.findBulletByCoord();
                }
                break;
            default:
                break;
        }
    }
    selectBullet(bullet: Bullet) {
        if (!this.ctrlNode.active) {
            this._selectBullets = [];
        }
        if (bullet) {
            if (!this._selectBullets.includes(bullet)) {
                this._selectBullets.push(bullet);
            }
            else {
                cc.js.array.remove(this._selectBullets, bullet);
            }
        }
        this.bulletInfo.setBullet(this._selectBullets.slice());
    }
    unselectBullet(bullet: Bullet) {
        if (this._selectBullets.includes(bullet)) {
            cc.js.array.remove(this._selectBullets, bullet);
            this.bulletInfo.setBullet(this._selectBullets.slice());
        }
    }
    onMouseMove(evt: cc.Event.EventMouse) {
        this.mouseInfo.update(evt);

        if (this.mouseInfo.btnRight) {
            let delta = this.mouseInfo.delta.div(this.interface.zoom);
            this.interface.camRn.node.x -= delta.x;
            this.interface.camRn.node.y -= delta.y;
        }
        this.updateCoord();
        switch (this.curToolInfo?.func) {
            case EditorToolItemFunc.Move:
                if (this._selectBullets.length === 0) {
                    return;
                }
                if (this.mouseInfo.btnLeft) {
                    let moveDelta = this.moveDelta;
                    if (this.shiftNode.active) {
                        moveDelta /= 2;
                    }

                    let isChanged = false;
                    let delta = this.mouseInfo.delta.div(this.interface.zoom);
                    if (this.altNode.active) {
                        this._selectBullets.forEach(bul => { bul.node.x += delta.x; bul.node.y += delta.y });
                        this.dragPos = cc.v2();
                        isChanged = true;
                    }
                    else {
                        this.dragPos = this.dragPos.add(delta);
                        if (this.dragPos.x > moveDelta) {
                            this.dragPos.x = 0;
                            this._selectBullets.forEach(bul => bul.node.x += moveDelta);
                            isChanged = true;
                        }
                        else if (this.dragPos.x < -moveDelta) {
                            this.dragPos.x = 0;
                            this._selectBullets.forEach(bul => bul.node.x -= moveDelta);
                            isChanged = true;
                        }
                        if (this.dragPos.y > moveDelta) {
                            this.dragPos.y = 0;
                            this._selectBullets.forEach(bul => bul.node.y += moveDelta);
                            isChanged = true;
                        }
                        else if (this.dragPos.y < -moveDelta) {
                            this.dragPos.y = 0;
                            this._selectBullets.forEach(bul => bul.node.y -= moveDelta);
                            isChanged = true;
                        }
                    }
                    if (isChanged) {
                        this._selectBullets.forEach(bul => bul.onMapEditorMove());
                        this.pushHistroy(this._save());
                    }
                }
                break;
            case EditorToolItemFunc.Size:
                if (this._selectBullets.length === 0) {
                    return;
                }
                if (this.mouseInfo.btnLeft) {
                    this.dragPos = this.dragPos.add(this.mouseInfo.delta.div(this.interface.zoom));
                    let isChanged = false;
                    if (this.dragPos.x > 100) {
                        this.dragPos.x = 0;
                        this._selectBullets.forEach(bul => {
                            bul.node.x += 50;
                            bul.node.width += 100;
                        });
                        isChanged = true;
                    }
                    else if (this.dragPos.x < -100) {
                        this.dragPos.x = 0;
                        this._selectBullets.forEach(bul => {
                            if (bul.node.width > 100) {
                                bul.node.width -= 100;
                                bul.node.x -= 50;
                            }
                        });
                        isChanged = true;
                    }
                    if (this.dragPos.y > 100) {
                        this.dragPos.y = 0;
                        this._selectBullets.forEach(bul => {
                            bul.node.height += 100;
                            bul.node.y += 50;
                        });
                        isChanged = true;
                    }
                    else if (this.dragPos.y < -100) {
                        this.dragPos.y = 0;
                        this._selectBullets.forEach(bul => {
                            if (bul.node.height > 100) {
                                bul.node.height -= 100;
                                bul.node.y -= 50;
                            }
                        });
                        isChanged = true;
                    }

                    if (isChanged) {
                        this._selectBullets.forEach(bul => bul.onMapEditorSizing());
                        this.pushHistroy(this._save());
                    }
                }
                break;
            default:
                break;
        }
    }
    holdingInd = 0;
    holdingBullets: Bullet[] = [];
    findBulletByCoord() {
        this.holdingBullets = [];
        this.holdingInd = 0;
        let wp = this.world.node.convertToWorldSpaceAR(this.worldCoord.mul(100));
        this.selectBullet(null);
        let bullets = this.world.getComponentsInChildren(Bullet);
        for (let i = 0; i < bullets.length; i++) {
            let bullet = bullets[i];
            if (!bullet.isCreateFromEditor) {
                continue;
            }
            if (bullet.physicsWorldRect.contains(wp)) {
                this.holdingBullets.push(bullet);
            }
        }

        // this.setCurBullet(bullet);
        // return this._curBullet;
    }
    updateCoord() {
        if (!this.world) {
            return;
        }
        let np = this.mouseInfo.loc;
        np = np.sub(this.gridOffset.mul(this.interface.zoom));
        let wp = cc.v2(this.interface.UIPointToWorld(np));
        let np2 = this.world.node.convertToNodeSpaceAR(wp);
        let coord2 = np2.div(100);
        coord2.x = Math.round(coord2.x) + this.gridOffset.x / 100;
        coord2.y = Math.round(coord2.y) + this.gridOffset.y / 100;

        this.worldCoord = coord2;

        let cursorPos = this.interface.worldPointToUI(coord2.mul(100), this.world.node);
        this.coordCursor.setPosition(cursorPos);
        this.coordCursor.scale = this.interface.zoom;
    }
    onMouseWheel(evt: cc.Event.EventMouse) {
        let sy = evt.getScrollY();

        if (this.holdingBullets.length > 0) {
            if (sy > 0) {
                this.holdingInd++;
                if (this.holdingInd >= this.holdingBullets.length) {
                    this.holdingInd = this.holdingBullets.length - 1;
                }
            }
            else {
                this.holdingInd--;
                if (this.holdingInd < 0) {
                    this.holdingInd = 0;
                }
            }
            this.selectBullet(this.holdingBullets[this.holdingInd]);
        }
        else {
            let tz = this.interface.zoom;
            if (sy > 0) {
                tz += 0.1;
            }
            else {
                tz -= 0.1;
            }
            tz = Math.floor(tz * 100) / 100;
            cc.Tween.stopAllByTarget(this.interface);
            cc.tween(this.interface).to(0.05, { zoom: tz }).start();
        }
    }
    onTouchStart(touch: TouchHandle) {
    }
    onTouchSingleMove(touch: TouchHandle) {
    }
    onTouchMutiMove(touchs: TouchHandle[]) {

    }
    onTouchEnd(touch: TouchHandle) {
    }

    curWorldInd = -1; //当前的配置在worldList的位置。
    async loadConfig(dat: WorldData) {
        await this.deleteWorld();
        this.world = BulletGameUtils.InstantiateWorld();
        this.node.addChild(this.world.node);
        this.bullets = this.world.initWithData(dat);
        this.refresh();

        this.attrContain.destroyAllChildren();
        let game = this.world.getComponent(World);
        if (game) {
            let eac = GetEditorAttrListByTarget(game);
            if (eac) {
                for (let i = 0; i < eac.items.length; i++) {
                    let eacItem = eac.items[i];
                    let key = eacItem.property;

                    let val = game[key];
                    let itemNode: cc.Node = null;
                    switch (true) {
                        case val instanceof cc.Vec2:
                            itemNode = cc.instantiate(this.attrItemVec2Prefab);
                            break;
                        case typeof val === "boolean":
                            itemNode = cc.instantiate(this.attrItemBooleanPrefab);
                            break;
                        default:
                            itemNode = cc.instantiate(this.attrItemPrefab);
                            break;
                    }

                    let item = itemNode.getComponent(BulletAttrItem);
                    item.setVal(eacItem.name, val);
                    this.attrContain.addChild(item.node);
                    item.on("edit", (newVal) => {
                        switch (true) {
                            case game[key] instanceof cc.Vec2:
                                game[key] = newVal;
                                break;
                            case typeof val === "boolean":
                                game[key] = newVal;
                                break;
                            case typeof game[key] == "number":
                                game[key] = Number(newVal);
                                break;
                            default:
                                game[key] = newVal;
                                break;
                        }
                        game.onMapEditorSetAttr(key);
                    }, this);
                }
            }
        }
        data.storage.set("editor-world-ind", this.curWorldInd);
    }
    async loadConfigByInd(dataInd: number) {
        this.curWorldInd = dataInd;
        let worldList: WorldData[] = data.storage.get<WorldData[]>("editor-world-list", []);
        this.loadConfig(worldList[dataInd]);
    }
    async newConfig(wd: WorldData) {
        this.curWorldInd = -1;
        this.loadConfig(wd);
    }

    async onClickLoad() {
        let box = Utils.game.pushBox("box_load_world").getComponent(BoxLoadWorld);
        box.once("load", (ind) => {
            this.loadConfigByInd(ind);
        }, this);
    }

    protected lateUpdate(dt: number): void {
        this.lbZoom.string = `${this.interface.zoom.toFixed(1)}`;
        this.lbPos.string = `${~~this.interface.camRn.node.x},${~~this.interface.camRn.node.y}`;
        let zoom = this.interface.zoom;
        let size = 100 * zoom;
        let wp = this.interface.cam.getScreenToWorldPoint(cc.v2(this.node.width / 2, this.node.height / 2));
        let oriPos = this.drawer.node.convertToNodeSpaceAR(wp);
        oriPos = oriPos.neg().mul(zoom);
        oriPos.x %= size;
        oriPos.y %= size;
        this.drawer.clear();
        this.drawer.fillColor = this.__normalFillColor;
        this.drawer.strokeColor = this.__normalStrokeColor;

        if (this.world) {

            if (this.cbGrid.checked) {
                let width = this.node.width;
                let height = this.node.height;

                // let countW = Math.ceil(width / size);
                // let countH = Math.ceil(height / size);
                let left = size * 25;
                for (let r = 0; r < 50; r++) {
                    let x = -left + r * size;
                    this.drawer.moveTo(oriPos.x + x, height / 2);
                    this.drawer.lineTo(oriPos.x + x, -height / 2);
                }

                let bottom = size * 25;
                for (let c = 0; c < 50; c++) {
                    let y = -bottom + c * size;
                    this.drawer.moveTo(width / 2, oriPos.y + y);
                    this.drawer.lineTo(-width / 2, oriPos.y + y);
                }
            }

            // let pt = this.world.bornNode.convertToWorldSpaceAR(cc.Vec2.ZERO);
            let pt = cc.v2(this.world.data.bornPointX * 100, this.world.data.bornPointY * 100);
            let np = this.interface.worldPointToUI(pt, this.world.node);
            this.drawer.circle(np.x, np.y, 25);


            // if (this.selectCoord) {
            //     let x = Math.ceil(oriPos.x + this.selectCoord.x * size);
            //     let y = Math.ceil(oriPos.y + this.selectCoord.y * size);

            //     this.drawer.fillColor = cc.Color.WHITE;
            //     this.drawer.fillRect(x, y, size, size);
            //     this.lbCoord.node.setPosition(x, y);
            //     this.lbCoord.string = `${this.selectCoord}`;

            // }

            // if (this.worldCoord) {
            //     let x = Math.ceil(oriPos.x + this.worldCoord.x * size);
            //     let y = Math.ceil(oriPos.y + this.worldCoord.y * size);

            //     this.drawer.fillColor = cc.Color.RED;
            //     this.drawer.fillRect(x, y, size, size);
            //     this.lbCoordWorld.node.setPosition(x, y);
            //     this.lbCoordWorld.string = `${this.worldCoord}`;
            // }
            this.drawer.stroke();
            this.drawer.fill();

            if (this._selectBullets.length !== 0) {
                this._selectBullets.forEach(bullet => {
                    let np = this.interface.worldPointToUI(bullet.curPos, bullet.world.node);
                    let w = bullet.node.width * this.interface.zoom + 10;
                    let h = bullet.node.height * this.interface.zoom + 10;

                    this.drawer.rect(
                        np.x - w * bullet.node.anchorX,
                        np.y - h * bullet.node.anchorY,
                        w,
                        h
                    );
                    if (bullet.lockInEditor) {
                        this.drawer.fillColor = cc.color(255, 0, 0, 100);
                        this.drawer.strokeColor = cc.color(255, 0, 0, 200);
                        this.drawer.stroke();
                        this.drawer.fill();
                    }
                    else {
                        this.drawer.fillColor = this.__normalFillColor;
                        this.drawer.strokeColor = this.__normalStrokeColor;
                        this.drawer.stroke();
                        this.drawer.fill();
                    }
                });
            }

            if (this._copyingBullets.length !== 0) {
                let tp = this.worldCoord.mul(100);
                // let tp = cc.v2();
                this._copyingBullets.forEach((bullet, ind) => {
                    let offset = this._copyingPosOffset[ind];
                    let pos = tp.add(offset);
                    let np = this.interface.worldPointToUI(pos, this.world.node);
                    this.drawer.circle(
                        np.x,
                        np.y,
                        50
                    );
                });
                this.drawer.fillColor = cc.color(255, 255, 0, 100);
                this.drawer.strokeColor = cc.color(255, 255, 0, 200);
                this.drawer.stroke();
                this.drawer.fill();
                this.drawer.fillColor = this.__normalFillColor;
                this.drawer.strokeColor = this.__normalStrokeColor;
            }
        }
    }
    onClickScale() {
        this.interface.zoom = 1;
    }

    onClickPos() {
        this.interface.camRn.node.setPosition(0, 0);
    }

    _save() {
        if (!this.world) {
            return;
        }
        let worldData = SerializeAble.Clone<WorldData>(this.worldConfigPanel.config);
        worldData.data = WorldDataReadWrite.SaveWorldData(this.world, this.bullets);

        let worldList: WorldData[] = data.storage.get("editor-world-list", []);
        if (this.curWorldInd === -1) {
            worldList.push(worldData);
            this.curWorldInd = worldList.length - 1;
        }
        else {
            worldList[this.curWorldInd] = worldData;
        }
        data.storage.set("editor-world-list", worldList);
        data.storage.set("editor-world-ind", this.curWorldInd);

        return worldData;
    }
    onClickSave() {
        let config = this._save();
        navigator.clipboard.writeText(JSON.stringify(config));
        console.log("已复制");
    }
    async onClickRun() {
        let config = this._save();
        await this.deleteWorld();
        Library.SetRecord(config);

        let gd = new GameData();
        gd.worldData = config;
        this.startSingleGame(gd);
    }

    async startSingleGame(gd: GameData) {
        Utils.blocker.show();
        data.cache.set("cur-game-data", gd);
        data.cache.set("prev-page", "page_map_editor");
        await Utils.game.replacePage({
            name: "page_game",
            ani: ReplacePageAni.Fade
        });
        Utils.blocker.hide();
    }

    onClickRevocation() {
        this.revocation();
    }
    async onClickExit() {
        Utils.game.replacePage({
            name: "PageLogin",
            ani: ReplacePageAni.Fade
        });
    }

    async onClickNew() {
        let config = SerializeAble.Clone<WorldData>(this.newWorldConfigPanel.config);
        this.newConfig(config);

    }
};